package com.ld.admin.shiro.config;

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.ld.admin.shiro.CustomRealm;
import com.ld.admin.shiro.cache.CaffeineCacheManager;
import com.ld.admin.shiro.filter.KickoutSessionControlFilter;
import com.ld.admin.shiro.filter.MyPermissionsAuthorizationFilter;
import com.ld.admin.shiro.filter.MyRolesAuthorizationFilter;
import com.ld.admin.shiro.filter.ShiroLoginFilter;
import com.ld.admin.shiro.filter.TokenCheckFilter;
import com.ld.admin.shiro.service.impl.ShiroServiceImpl;
import com.ld.shieldsb.common.composition.util.web.Global;
import com.ld.shieldsb.common.core.model.PropertiesModel;

@Configuration
@AutoConfigureOrder(2)
public class ShiroConfig {
    protected String adminPath = Global.PROJECT_ADMIN_S;
    protected String frontPath = Global.PROJECT_FRONT_S;

    @Bean
    public ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager, ShiroServiceImpl shiroService) {
        System.out.println(new Date() + "Shiro拦截器工厂类开始注入");
        boolean kickoutEnable = PropertiesModel.CONFIG.getBoolean("shiro.kickout.enable", false); // 踢人功能
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // setLoginUrl 如果不设置值，默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射,已经重新定义了authc的过滤器，此配置可取消
        shiroFilterFactoryBean.setLoginUrl(adminPath + "/toLogin");
        // 登录成功后跳转的主页面 （这里没用，已经控制了跳转）
//      shiroFilterFactoryBean.setSuccessUrl("/index");
        // 设置无权限时跳转的 url;
//        shiroFilterFactoryBean.setUnauthorizedUrl(adminPath + "/notRole"); //可不配置

        // 自定义过滤器
        Map<String, Filter> filtersMap = new LinkedHashMap<>();
        // 定义过滤器名称 【注：map里面key值对于的value要为authc才能使用自定义的过滤器】
        if (kickoutEnable) {
            filtersMap.put("kickout", kickoutSessionControlFilter());
        }
        filtersMap.put("authc", new ShiroLoginFilter()); // 替换默认的org.apache.shiro.web.filter.authc.FormAuthenticationFilter
        filtersMap.put("zqPerms", new MyPermissionsAuthorizationFilter());
        filtersMap.put("zqRoles", new MyRolesAuthorizationFilter());
        filtersMap.put("token", new TokenCheckFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);

        /*// 设置拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 获取权限与角色的对应关系
        
        // 游客，开发权限
        filterChainDefinitionMap.put("/guest/**", "anon");
        // 用户，需要角色权限 “user”
        filterChainDefinitionMap.put("/user/**", "roles[user]");
        // 管理员，需要角色权限 “admin”
        filterChainDefinitionMap.put("/admin/**", "roles[admin]");
        // 开放登陆接口
        filterChainDefinitionMap.put(adminPath + "/login", "anon");
        // 其余接口一律拦截
        // 主要这行代码必须放在所有权限设置的最后，不然会导致所有 url 都被拦截
        filterChainDefinitionMap.put(adminPath + "/**", "authc"); // ,token,zqPerms[user1]
        */
        shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroService.loadFilterChainDefinitionMap());
        System.out.println(new Date() + "Shiro拦截器工厂类注入成功");
        return shiroFilterFactoryBean;
    }

    /**
     * 注入 securityManager
     */
    @Bean
    public org.apache.shiro.mgt.SecurityManager securityManager(CustomRealm customRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 注入自定义的realm;
        securityManager.setRealm(customRealm);
        System.out.println(securityManager.getSessionManager());
        // 注入缓存管理器;
//        securityManager.setCacheManager(shiroCacheManager());
        // 自定义session管理 添加自定义session管理，解决 异常 sessionId（无效）冲突问题。
//        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * 限制同一账号登录同时登录人数控制
     *
     * @return
     */
    public KickoutSessionControlFilter kickoutSessionControlFilter() {
        KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
        // 用于根据会话ID，获取会话进行踢出操作的；
//        kickoutSessionControlFilter.setSessionManager(((DefaultWebSecurityManager) securityManager).getSessionManager());
        // 使用cacheManager获取相应的cache来缓存用户登录的会话；用于保存用户—会话之间的关系的；
        kickoutSessionControlFilter.setCacheManager(shiroCacheManager());
        // 是否踢出后来登录的，默认是false；即后者登录的用户踢出前者登录的用户；
//        kickoutSessionControlFilter.setKickoutAfter(false);
        // 同一个用户最大的会话数，默认1；比如2的意思是同一个用户允许最多同时两个人登录；
//        kickoutSessionControlFilter.setMaxSession(1);
        // 被踢出后重定向到的地址；
//        kickoutSessionControlFilter.setKickoutUrl("/land?kickout=1");
        return kickoutSessionControlFilter;
    }

    /*
     * shiro缓存管理器;
     * 需要注入对应的其它的实体类中-->安全管理器：securityManager可见securityManager是整个shiro的核心；
     */
    @Bean
    public CaffeineCacheManager shiroCacheManager() {
        CaffeineCacheManager ehcache = new CaffeineCacheManager();
        return ehcache;
    }
}
